﻿using OrBitDataModule;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.Xml;
using System.IO.Ports;
using NLog;
using OrBitDataModule.Interface;
using OrBitDataModule.Common;
using System.Diagnostics;
using OrBitDataModule.Adaptor;
using Logger = OrBitDataModule.Common.Logger;

namespace OrBitDataModule.Base
{
    /// <summary>
    /// 任务基础类，新建任务需继承此类
    /// </summary>
    public abstract class DataTaskBase
    {
        /// <summary>
        /// APP context
        /// </summary>
        public abstract IContext Context { get; set; }
        /// <summary>
        /// 运行状态改变
        /// </summary>
        public abstract event EventHandler<TaskEventArgs> OnStateChange;

        /// <summary>
        /// 日志时间
        /// </summary>
        public event EventHandler<string> OnLogEvent;
        /// <summary>
        /// 任务唯一码
        /// </summary>
        public abstract string UniqueId { get; }

        /// <summary>
        /// 配置参数Json
        /// </summary>
        public abstract string ConfigJson { get; }

        /// <summary>
        /// 默认编码
        /// </summary>
        public abstract Encoding DefaultEncoding { get; }

        /// <summary>
        /// 脚本名称
        /// </summary>
        public abstract string ScriptName { get; set; }
        /// <summary>
        /// 脚本代码
        /// </summary>
        public abstract string ScriptCode { get; set; }

        /// <summary>
        /// 脚本代码
        /// </summary>
        public abstract ScriptBase Script { get; set; }

        /// <summary>
        /// 脚本运行对象
        /// </summary>
        public abstract ScriptRunner ScripterRunner { set; get; }
        /// <summary>
        /// 脚本ID
        /// </summary>
        public abstract string DataProtocolScriptId { get; }

        /// <summary>
        /// 是否在调试中
        /// </summary>
        public abstract bool IsScripDebug { get; set; }

        /// <summary>
        /// 任务执行时事件
        /// </summary>
        public abstract void OnLoad();

        /// <summary>
        /// 启动任务
        /// </summary>
        public abstract void Start();

        /// <summary>
        /// 停止任务
        /// </summary>
        public abstract void Stop();

        /// <summary>
        /// 销毁对象时
        /// </summary>
        public abstract void OnDispose();

        /// <summary>
        /// 处理外部消息发送
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public abstract string SendExternal(string message);

        /// <summary>
        /// 获取token起始时间
        /// </summary>
        public DateTime TokenStartTime { set; get; } = DateTime.Now;

        /// <summary>
        /// 是否可以执行脚本方法
        /// </summary>
        public bool CanRunScript { get; private set; } = false;

        /// <summary>
        /// 设置参数
        /// </summary>
        public SettingDictionary SettingProperty { get; internal set; }

        /// <summary>
        /// 任务运行参数
        /// </summary>
        public Dictionary<string, string> Parameters => LocalSetting.GetConfig(this.UniqueId).parameters;

        /// <summary>
        /// 串口对象
        /// </summary>
        public abstract SerialPort SerialPortInstance { get; set; }

        /// <summary>
        /// Socket Client对象
        /// </summary>
        public abstract SocketTcpClient TcpClientInstance { get; set; }

        /// <summary>
        /// 获取登录token,检查token有效期
        /// </summary>
        public void GetWebApiToken()
        {
            try
            {
                if (Expiration == -1 && !string.IsNullOrWhiteSpace(Token))
                {
                    return;
                }
                else if (Expiration > 0)
                {
                    TimeSpan timeDifference = DateTime.Now - TokenStartTime;
                    int minutesDifference = (int)timeDifference.TotalMinutes;
                    if (minutesDifference < Expiration)
                    {
                        return;
                    }
                }
                else
                {
                    var result = WebApi.GetAccessToken(ApiName, UserName, Password);
                    if (result.Result)
                    {
                        this.Token = result.Token;
                        this.Expiration = result.Expiration;
                        this.TokenStartTime = DateTime.Now;
                    }
                    else
                    {
                        WriteLog($"获取接口token失败，信息:{result.Message}", LogLevel.Error);
                        this.Expiration = 0;
                        this.Token = string.Empty;
                    }
                }
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
            }
        }

        /// <summary>
        /// 编译脚本
        /// </summary>
        public void CompileScript()
        {
            try
            {
                if (!this.IsScripDebug)
                {
                    this.Context = new Context(this);

                    ScripterRunner.ScriptCpde = this.ScriptCode;
                    var result = ScripterRunner.CompileScript(Context);
                    if (result.Result)
                    {
                        WriteLog("脚本编译成功");
                        Script = ScripterRunner.Script;
                        this.CanRunScript = true;
                    }
                    else
                    {
                        WriteLog($"脚本编译失败，错误信息：{result.Message}");
                        this.CanRunScript = false;
                    }
                }
                else
                {
                    this.CanRunScript = true;
                }
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
                this.CanRunScript = false;
            }
        }

        ///// <summary>
        ///// 向WebApi提交
        ///// </summary>
        //public abstract void Submit(string fileName, string content);

        /// <summary>
        /// 任务协议类型
        /// </summary>
        public abstract string TaskProtocolType { get; }


        /// <summary>
        /// 任务名称
        /// </summary>
        public abstract string TaskName { get; }

        /// <summary>
        /// Webapi基础地址
        /// </summary>
        public string BaseApiUri { get => ConfigHelper.GetValue("BaseApiUri"); }

        /// <summary>
        /// 接口用户名
        /// </summary>
        public abstract string UserName { get; }

        /// <summary>
        /// 接口密码
        /// </summary>
        public abstract string Password { get; }

        /// <summary>
        /// 接口名称
        /// </summary>
        public abstract string ApiName { get; }

        /// <summary>
        /// 登录接口token
        /// 
        /// </summary>
        public abstract string Token { get; set; }
        /// <summary>
        /// 接口有效期
        /// </summary>
        public abstract int Expiration { get; set; }


        /// <summary>
        /// /序列化json
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public string SerializeToJson<T>(T obj) => JsonConvert.SerializeObject(obj);

        /// <summary> 
        /// 实体对象序列化成xml字符串 
        /// </summary> 
        /// <typeparam name="T"></typeparam> 
        /// <param name="obj"></param> 
        /// <returns></returns> 
        public string SerializeToXML<T>(T obj, Encoding encoding = null)
        {
            try
            {
                if (encoding == null)
                {
                    encoding = Encoding.Default;
                }
                var ser = new XmlSerializer(obj.GetType());
                using (var ms = new MemoryStream())
                {
                    using (var writer = new XmlTextWriter(ms, encoding))
                    {
                        writer.Formatting = System.Xml.Formatting.Indented;
                        ser.Serialize(writer, obj);
                    }
                    var xml = encoding.GetString(ms.ToArray());
                    xml = xml.Replace("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
                    xml = xml.Replace("xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", "");
                    xml = Regex.Replace(xml, @"\s{2}", "");
                    xml = Regex.Replace(xml, @"\s{1}/>", "/>");
                    return xml;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public void WriteLog(string message, [CallerLineNumber] int sourceLineNumber = 0, [CallerMemberName] string callerMemberName = "") => WriteLog(message, LogLevel.Info, sourceLineNumber, callerMemberName);

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="logLevel"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public void WriteLog(string message, LogLevel logLevel, int sourceLineNumber = 0, string callerMemberName = "") => WriteLog(this.TaskName, message, logLevel, sourceLineNumber, callerMemberName);

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="taskName"></param>
        /// <param name="message"></param>
        /// <param name="logLevel"></param>
        /// <returns></returns>
        public void WriteLog(string taskName, string message, LogLevel logLevel, int sourceLineNumber, string callerMemberName)
        {

#if DEBUG
            string log = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}| CallerMemberName = {callerMemberName} | CallerLineNumber = {sourceLineNumber} |{logLevel.Name}| 任务名称:{taskName} | 任务类型:{TaskProtocolType} | {message}";
            OnLogEvent?.Invoke(this, log);
            Logger.Log(message, logLevel);
#else
            string log = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}|{logLevel.Name}| 任务名称:{taskName} | 任务类型:{TaskProtocolType} | {message}";
            OnLogEvent?.Invoke(this, log);
            OrBitDataModule.Logger.Log(message, logLevel);
#endif


        }
    }
}
